/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef jit_SharedIC_h#define jit_SharedIC_h#include"jscntxt.h"#include"jscompartment.h"#include"jsgc.h"#include"jit/BaselineICList.h"#include"jit/BaselineJIT.h"#include"jit/ICState.h"#include"jit/MacroAssembler.h"#include"jit/SharedICList.h"#include"jit/SharedICRegisters.h"#include"vm/ReceiverGuard.h"#include"vm/TypedArrayObject.h"namespacejs{namespacejit{//// Baseline Inline Caches are polymorphic caches that aggressively// share their stub code.//// Every polymorphic site contains a linked list of stubs which are// specific to that site. These stubs are composed of a |StubData|// structure that stores parametrization information (e.g.// the shape pointer for a shape-check-and-property-get stub), any// dynamic information (e.g. warm-up counters), a pointer to the stub code,// and a pointer to the next stub state in the linked list.//// Every BaselineScript keeps an table of |CacheDescriptor| data// structures, which store the following:// A pointer to the first StubData in the cache.// The bytecode PC of the relevant IC.// The machine-code PC where the call to the stubcode returns.//// A diagram://// Control flow Pointers// =======# ----. .---->// # | |// #======> \-----/////// .---------------------------------------.// | .-------------------------. |// | | .----. | |// Baseline | | | | | |// JIT Code 0 ^ 1 ^ 2 ^ | | |// +--------------+ .-->+-----+ +-----+ +-----+ | | |// | | #=|==>| |==>| |==>| FB | | | |// | | # | +-----+ +-----+ +-----+ | | |// | | # | # # # | | |// |==============|==# | # # # | | |// |=== IC =======| | # # # | | |// .->|==============|<===|======#=========#=========# | | |// | | | | | | |// | | | | | | |// | | | | | | |// | | | | v | |// | | | | +---------+ | |// | | | | | Fallback| | |// | | | | | Stub | | |// | | | | | Code | | |// | | | | +---------+ | |// | +--------------+ | | |// | |_______ | +---------+ | |// | | | | Stub |<---/ |// | IC | \--. | Code | |// | Descriptor | | +---------+ |// | Table v | |// | +-----------------+ | +---------+ |// \--| Ins | PC | Stub |----/ | Stub |<-------/// +-----------------+ | Code |// | ... | +---------+// +-----------------+// Shared// Stub Code////// Type ICs// ========//// Type ICs are otherwise regular ICs that are actually nested within// other IC chains. They serve to optimize locations in the code where the// baseline compiler would have otherwise had to perform a type Monitor operation// (e.g. the result of GetProp, GetElem, etc.), or locations where the baseline// compiler would have had to modify a heap typeset using the type of an input// value (e.g. SetProp, SetElem, etc.)//// There are two kinds of Type ICs: Monitor and Update.//// Note that type stub bodies are no-ops. The stubs only exist for their// guards, and their existence simply signifies that the typeset (implicit)// that is being checked already contains that type.//// TypeMonitor ICs// ---------------// Monitor ICs are shared between stubs in the general IC, and monitor the resulting// types of getter operations (call returns, getprop outputs, etc.)//// +-----------+ +-----------+ +-----------+ +-----------+// ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |// +-----------+ +-----------+ +-----------+ +-----------+// | | | |// |------------------/-----------------/ |// v |// +-----------+ +-----------+ +-----------+ |// | Type 1 |---->| Type 2 |---->| Type FB | |// +-----------+ +-----------+ +-----------+ |// | | | |// <----------/-----------------/------------------/------------------/// r e t u r n p a t h//// After an optimized IC stub successfully executes, it passes control to the type stub// chain to check the resulting type. If no type stub succeeds, and the monitor fallback// stub is reached, the monitor fallback stub performs a manual monitor, and also adds the// appropriate type stub to the chain.//// The IC's main fallback, in addition to generating new mainline stubs, also generates// type stubs as reflected by its returned value.//// NOTE: The type IC chain returns directly to the mainline code, not back to the// stub it was entered from. Thus, entering a type IC is a matter of a |jump|, not// a |call|. This allows us to safely call a VM Monitor function from within the monitor IC's// fallback chain, since the return address (needed for stack inspection) is preserved.////// TypeUpdate ICs// --------------// Update ICs update heap typesets and monitor the input types of setter operations// (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not shared// between stubs on an IC, but instead are kept track of on a per-stub basis.//// This is because the main stubs for the operation will each identify a potentially// different ObjectGroup to update. New input types must be tracked on a group-to-// group basis.//// Type-update ICs cannot be called in tail position (they must return to the// the stub that called them so that the stub may continue to perform its original// purpose). This means that any VMCall to perform a manual type update from C++ must be// done from within the main IC stub. This necessitates that the stub enter a// "BaselineStub" frame before making the call.//// If the type-update IC chain could itself make the VMCall, then the BaselineStub frame// must be entered before calling the type-update chain, and exited afterward. This// is very expensive for a common case where we expect the type-update fallback to not// be called. To avoid the cost of entering and exiting a BaselineStub frame when// using the type-update IC chain, we design the chain to not perform any VM-calls// in its fallback.//// Instead, the type-update IC chain is responsible for returning 1 or 0, depending// on if a type is represented in the chain or not. The fallback stub simply returns// 0, and all other optimized stubs return 1.// If the chain returns 1, then the IC stub goes ahead and performs its operation.// If the chain returns 0, then the IC stub performs a call to the fallback function// inline (doing the requisite BaselineStub frame enter/exit).// This allows us to avoid the expensive subfram enter/exit in the common case.//// r e t u r n p a t h// <--------------.-----------------.-----------------.-----------------.// | | | |// +-----------+ +-----------+ +-----------+ +-----------+// ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |// +-----------+ +-----------+ +-----------+ +-----------+// | ^ | ^ | ^// | | | | | |// | | | | | |----------------.// | | | | v |1 |0// | | | | +-----------+ +-----------+// | | | | | Type 3.1 |--->| FB 3 |// | | | | +-----------+ +-----------+// | | | |// | | | \-------------.-----------------.// | | | | | |// | | v |1 |1 |0// | | +-----------+ +-----------+ +-----------+// | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 |// | | +-----------+ +-----------+ +-----------+// | |// | \-------------.-----------------.// | | | |// v |1 |1 |0// +-----------+ +-----------+ +-----------+// | Type 1.1 |---->| Type 1.2 |---->| FB 1 |// +-----------+ +-----------+ +-----------+//classICStub;classICFallbackStub;#define FORWARD_DECLARE_STUBS(kindName) class IC##kindName;IC_BASELINE_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)IC_SHARED_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)#undef FORWARD_DECLARE_STUBS#ifdef JS_JITSPEWvoidFallbackICSpew(JSContext*cx,ICFallbackStub*stub,constchar*fmt,...)MOZ_FORMAT_PRINTF(3,4);voidTypeFallbackICSpew(JSContext*cx,ICTypeMonitor_Fallback*stub,constchar*fmt,...)MOZ_FORMAT_PRINTF(3,4);#else#define FallbackICSpew(...)#define TypeFallbackICSpew(...)#endif//// An entry in the JIT IC descriptor table.//classICEntry{private:// A pointer to the shared IC stub for this instruction.ICStub*firstStub_;// Offset from the start of the JIT code where the IC// load and call instructions are.uint32_treturnOffset_;// The PC of this IC's bytecode op within the JSScript.uint32_tpcOffset_:28;public:enumKind{// A for-op IC entry.Kind_Op=0,// A non-op IC entry.Kind_NonOp,// A fake IC entry for returning from a callVM for an op.Kind_CallVM,// A fake IC entry for returning from a callVM not for an op (e.g., in// the prologue).Kind_NonOpCallVM,// A fake IC entry for returning from a callVM to after the// warmup counter.Kind_WarmupCounter,// A fake IC entry for returning from a callVM to the interrupt// handler via the over-recursion check on function entry.Kind_StackCheck,// As above, but for the early check. See emitStackCheck.Kind_EarlyStackCheck,// A fake IC entry for returning from DebugTrapHandler.Kind_DebugTrap,// A fake IC entry for returning from a callVM to// Debug{Prologue,Epilogue}.Kind_DebugPrologue,Kind_DebugEpilogue,Kind_Invalid};private:// What this IC is for.Kindkind_:4;// Set the kind and asserts that it's sane.voidsetKind(Kindkind){MOZ_ASSERT(kind<Kind_Invalid);kind_=kind;MOZ_ASSERT(this->kind()==kind);}public:ICEntry(uint32_tpcOffset,Kindkind):firstStub_(nullptr),returnOffset_(),pcOffset_(pcOffset){// The offset must fit in at least 28 bits, since we shave off 4 for// the Kind enum.MOZ_ASSERT(pcOffset_==pcOffset);JS_STATIC_ASSERT(BaselineScript::MAX_JSSCRIPT_LENGTH<=(1u<<28)-1);MOZ_ASSERT(pcOffset<=BaselineScript::MAX_JSSCRIPT_LENGTH);setKind(kind);}CodeOffsetreturnOffset()const{returnCodeOffset(returnOffset_);}voidsetReturnOffset(CodeOffsetoffset){MOZ_ASSERT(offset.offset()<=(size_t)UINT32_MAX);returnOffset_=(uint32_t)offset.offset();}uint32_tpcOffset()const{returnpcOffset_;}jsbytecode*pc(JSScript*script)const{returnscript->offsetToPC(pcOffset_);}Kindkind()const{// MSVC compiles enums as signed.returnKind(kind_&0xf);}boolisForOp()const{returnkind()==Kind_Op;}voidsetFakeKind(Kindkind){MOZ_ASSERT(kind!=Kind_Op&&kind!=Kind_NonOp);setKind(kind);}boolhasStub()const{returnfirstStub_!=nullptr;}ICStub*firstStub()const{MOZ_ASSERT(hasStub());returnfirstStub_;}ICFallbackStub*fallbackStub()const;voidsetFirstStub(ICStub*stub){firstStub_=stub;}staticinlinesize_toffsetOfFirstStub(){returnoffsetof(ICEntry,firstStub_);}inlineICStub**addressOfFirstStub(){return&firstStub_;}protected:voidtraceEntry(JSTracer*trc);};classBaselineICEntry:publicICEntry{public:BaselineICEntry(uint32_tpcOffset,Kindkind):ICEntry(pcOffset,kind){}voidtrace(JSTracer*trc);};classIonICEntry:publicICEntry{JSScript*script_;public:IonICEntry(uint32_tpcOffset,Kindkind,JSScript*script):ICEntry(pcOffset,kind),script_(script){}JSScript*script(){returnscript_;}voidtrace(JSTracer*trc);};classICMonitoredStub;classICMonitoredFallbackStub;classICUpdatedStub;// Constant iterator that traverses arbitrary chains of ICStubs.// No requirements are made of the ICStub used to construct this// iterator, aside from that the stub be part of a nullptr-terminated// chain.// The iterator is considered to be at its end once it has been// incremented _past_ the last stub. Thus, if 'atEnd()' returns// true, the '*' and '->' operations are not valid.classICStubConstIterator{friendclassICStub;friendclassICFallbackStub;private:ICStub*currentStub_;public:explicitICStubConstIterator(ICStub*currentStub):currentStub_(currentStub){}staticICStubConstIteratorStartingAt(ICStub*stub){returnICStubConstIterator(stub);}staticICStubConstIteratorEnd(ICStub*stub){returnICStubConstIterator(nullptr);}booloperator==(constICStubConstIterator&other)const{returncurrentStub_==other.currentStub_;}booloperator!=(constICStubConstIterator&other)const{return!(*this==other);}ICStubConstIterator&operator++();ICStubConstIteratoroperator++(int){ICStubConstIteratoroldThis(*this);++(*this);returnoldThis;}ICStub*operator*()const{MOZ_ASSERT(currentStub_);returncurrentStub_;}ICStub*operator->()const{MOZ_ASSERT(currentStub_);returncurrentStub_;}boolatEnd()const{returncurrentStub_==nullptr;}};// Iterator that traverses "regular" IC chains that start at an ICEntry// and are terminated with an ICFallbackStub.//// The iterator is considered to be at its end once it is _at_ the// fallback stub. Thus, unlike the ICStubConstIterator, operators// '*' and '->' are valid even if 'atEnd()' returns true - they// will act on the fallback stub.//// This iterator also allows unlinking of stubs being traversed.// Note that 'unlink' does not implicitly advance the iterator -// it must be advanced explicitly using '++'.classICStubIterator{friendclassICFallbackStub;private:ICEntry*icEntry_;ICFallbackStub*fallbackStub_;ICStub*previousStub_;ICStub*currentStub_;boolunlinked_;explicitICStubIterator(ICFallbackStub*fallbackStub,boolend=false);public:booloperator==(constICStubIterator&other)const{// == should only ever be called on stubs from the same chain.MOZ_ASSERT(icEntry_==other.icEntry_);MOZ_ASSERT(fallbackStub_==other.fallbackStub_);returncurrentStub_==other.currentStub_;}booloperator!=(constICStubIterator&other)const{return!(*this==other);}ICStubIterator&operator++();ICStubIteratoroperator++(int){ICStubIteratoroldThis(*this);++(*this);returnoldThis;}ICStub*operator*()const{returncurrentStub_;}ICStub*operator->()const{returncurrentStub_;}boolatEnd()const{returncurrentStub_==(ICStub*)fallbackStub_;}voidunlink(JSContext*cx);};//// Base class for all IC stubs.//classICStub{friendclassICFallbackStub;public:enumKind{INVALID=0,#define DEF_ENUM_KIND(kindName) kindName,IC_BASELINE_STUB_KIND_LIST(DEF_ENUM_KIND)IC_SHARED_STUB_KIND_LIST(DEF_ENUM_KIND)#undef DEF_ENUM_KINDLIMIT};staticboolIsValidKind(Kindk){return(k>INVALID)&&(k<LIMIT);}staticboolIsCacheIRKind(Kindk){returnk==CacheIR_Regular||k==CacheIR_Monitored||k==CacheIR_Updated;}staticconstchar*KindString(Kindk){switch(k){#define DEF_KIND_STR(kindName) case kindName: return #kindName;IC_BASELINE_STUB_KIND_LIST(DEF_KIND_STR)IC_SHARED_STUB_KIND_LIST(DEF_KIND_STR)#undef DEF_KIND_STRdefault:MOZ_CRASH("Invalid kind.");}}enumTrait{Regular=0x0,Fallback=0x1,Monitored=0x2,MonitoredFallback=0x3,Updated=0x4};voidtraceCode(JSTracer*trc,constchar*name);voidupdateCode(JitCode*stubCode);voidtrace(JSTracer*trc);template<typenameT,typename...Args>staticT*New(JSContext*cx,ICStubSpace*space,JitCode*code,Args&&...args){if(!code)returnnullptr;T*result=space->allocate<T>(code,mozilla::Forward<Args>(args)...);if(!result)ReportOutOfMemory(cx);returnresult;}protected:// The raw jitcode to call for this stub.uint8_t*stubCode_;// Pointer to next IC stub. This is null for the last IC stub, which should// either be a fallback or inert IC stub.ICStub*next_;// A 16-bit field usable by subtypes of ICStub for subtype-specific small-infouint16_textra_;// The kind of the stub.// High bit is 'isFallback' flag.// Second high bit is 'isMonitored' flag.Traittrait_:3;Kindkind_:13;inlineICStub(Kindkind,JitCode*stubCode):stubCode_(stubCode->raw()),next_(nullptr),extra_(0),trait_(Regular),kind_(kind){MOZ_ASSERT(stubCode!=nullptr);}inlineICStub(Kindkind,Traittrait,JitCode*stubCode):stubCode_(stubCode->raw()),next_(nullptr),extra_(0),trait_(trait),kind_(kind){MOZ_ASSERT(stubCode!=nullptr);}inlineTraittrait()const{// Workaround for MSVC reading trait_ as signed value.return(Trait)(trait_&0x7);}public:inlineKindkind()const{returnstatic_cast<Kind>(kind_);}inlineboolisFallback()const{returntrait()==Fallback||trait()==MonitoredFallback;}inlineboolisMonitored()const{returntrait()==Monitored;}inlineboolisUpdated()const{returntrait()==Updated;}inlineboolisMonitoredFallback()const{returntrait()==MonitoredFallback;}inlineconstICFallbackStub*toFallbackStub()const{MOZ_ASSERT(isFallback());returnreinterpret_cast<constICFallbackStub*>(this);}inlineICFallbackStub*toFallbackStub(){MOZ_ASSERT(isFallback());returnreinterpret_cast<ICFallbackStub*>(this);}inlineconstICMonitoredStub*toMonitoredStub()const{MOZ_ASSERT(isMonitored());returnreinterpret_cast<constICMonitoredStub*>(this);}inlineICMonitoredStub*toMonitoredStub(){MOZ_ASSERT(isMonitored());returnreinterpret_cast<ICMonitoredStub*>(this);}inlineconstICMonitoredFallbackStub*toMonitoredFallbackStub()const{MOZ_ASSERT(isMonitoredFallback());returnreinterpret_cast<constICMonitoredFallbackStub*>(this);}inlineICMonitoredFallbackStub*toMonitoredFallbackStub(){MOZ_ASSERT(isMonitoredFallback());returnreinterpret_cast<ICMonitoredFallbackStub*>(this);}inlineconstICUpdatedStub*toUpdatedStub()const{MOZ_ASSERT(isUpdated());returnreinterpret_cast<constICUpdatedStub*>(this);}inlineICUpdatedStub*toUpdatedStub(){MOZ_ASSERT(isUpdated());returnreinterpret_cast<ICUpdatedStub*>(this);}#define KIND_METHODS(kindName) \ inline bool is##kindName() const { return kind() == kindName; } \ inline const IC##kindName* to##kindName() const { \ MOZ_ASSERT(is##kindName()); \ return reinterpret_cast<const IC##kindName*>(this); \ } \ inline IC##kindName* to##kindName() { \ MOZ_ASSERT(is##kindName()); \ return reinterpret_cast<IC##kindName*>(this); \ }IC_BASELINE_STUB_KIND_LIST(KIND_METHODS)IC_SHARED_STUB_KIND_LIST(KIND_METHODS)#undef KIND_METHODSinlineICStub*next()const{returnnext_;}inlineboolhasNext()const{returnnext_!=nullptr;}inlinevoidsetNext(ICStub*stub){// Note: next_ only needs to be changed under the compilation lock for// non-type-monitor/update ICs.next_=stub;}inlineICStub**addressOfNext(){return&next_;}inlineJitCode*jitCode(){returnJitCode::FromExecutable(stubCode_);}inlineuint8_t*rawStubCode()const{returnstubCode_;}// This method is not valid on TypeUpdate stub chains!inlineICFallbackStub*getChainFallback(){ICStub*lastStub=this;while(lastStub->next_)lastStub=lastStub->next_;MOZ_ASSERT(lastStub->isFallback());returnlastStub->toFallbackStub();}inlineICStubConstIteratorbeginHere(){returnICStubConstIterator::StartingAt(this);}staticinlinesize_toffsetOfNext(){returnoffsetof(ICStub,next_);}staticinlinesize_toffsetOfStubCode(){returnoffsetof(ICStub,stubCode_);}staticinlinesize_toffsetOfExtra(){returnoffsetof(ICStub,extra_);}staticboolNonCacheIRStubMakesGCCalls(Kindkind);boolmakesGCCalls()const;// Optimized stubs get purged on GC. But some stubs can be active on the// stack during GC - specifically the ones that can make calls. To ensure// that these do not get purged, all stubs that can make calls are allocated// in the fallback stub space.boolallocatedInFallbackSpace()const{MOZ_ASSERT(next());returnmakesGCCalls();}};classICFallbackStub:publicICStub{friendclassICStubConstIterator;protected:// Fallback stubs need these fields to easily add new stubs to// the linked list of stubs for an IC.// The IC entry for this linked list of stubs.ICEntry*icEntry_;// The number of stubs kept in the IC entry.ICStatestate_;// A pointer to the location stub pointer that needs to be// changed to add a new "last" stub immediately before the fallback// stub. This'll start out pointing to the icEntry's "firstStub_"// field, and as new stubs are added, it'll point to the current// last stub's "next_" field.ICStub**lastStubPtrAddr_;ICFallbackStub(Kindkind,JitCode*stubCode):ICStub(kind,ICStub::Fallback,stubCode),icEntry_(nullptr),state_(),lastStubPtrAddr_(nullptr){}ICFallbackStub(Kindkind,Traittrait,JitCode*stubCode):ICStub(kind,trait,stubCode),icEntry_(nullptr),state_(),lastStubPtrAddr_(nullptr){MOZ_ASSERT(trait==ICStub::Fallback||trait==ICStub::MonitoredFallback);}public:inlineICEntry*icEntry()const{returnicEntry_;}inlinesize_tnumOptimizedStubs()const{returnstate_.numOptimizedStubs();}voidsetInvalid(){state_.setInvalid();}boolinvalid()const{returnstate_.invalid();}ICState&state(){returnstate_;}// The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is// created since the stub is created at compile time, and we won't know the IC entry// address until after compile when the JitScript is created. This method// allows these fields to be fixed up at that point.voidfixupICEntry(ICEntry*icEntry){MOZ_ASSERT(icEntry_==nullptr);MOZ_ASSERT(lastStubPtrAddr_==nullptr);icEntry_=icEntry;lastStubPtrAddr_=icEntry_->addressOfFirstStub();}// Add a new stub to the IC chain terminated by this fallback stub.voidaddNewStub(ICStub*stub){MOZ_ASSERT(!invalid());MOZ_ASSERT(*lastStubPtrAddr_==this);MOZ_ASSERT(stub->next()==nullptr);stub->setNext(this);*lastStubPtrAddr_=stub;lastStubPtrAddr_=stub->addressOfNext();state_.trackAttached();}ICStubConstIteratorbeginChainConst()const{returnICStubConstIterator(icEntry_->firstStub());}ICStubIteratorbeginChain(){returnICStubIterator(this);}boolhasStub(ICStub::Kindkind)const{for(ICStubConstIteratoriter=beginChainConst();!iter.atEnd();iter++){if(iter->kind()==kind)returntrue;}returnfalse;}unsignednumStubsWithKind(ICStub::Kindkind)const{unsignedcount=0;for(ICStubConstIteratoriter=beginChainConst();!iter.atEnd();iter++){if(iter->kind()==kind)count++;}returncount;}voiddiscardStubs(JSContext*cx);voidunlinkStub(Zone*zone,ICStub*prev,ICStub*stub);voidunlinkStubsWithKind(JSContext*cx,ICStub::Kindkind);};// Base class for Trait::Regular CacheIR stubsclassICCacheIR_Regular:publicICStub{constCacheIRStubInfo*stubInfo_;public:ICCacheIR_Regular(JitCode*stubCode,constCacheIRStubInfo*stubInfo):ICStub(ICStub::CacheIR_Regular,stubCode),stubInfo_(stubInfo){}voidnotePreliminaryObject(){extra_=1;}boolhasPreliminaryObject()const{returnextra_;}constCacheIRStubInfo*stubInfo()const{returnstubInfo_;}uint8_t*stubDataStart();};// Monitored stubs are IC stubs that feed a single resulting value out to a// type monitor operation.classICMonitoredStub:publicICStub{protected:// Pointer to the start of the type monitoring stub chain.ICStub*firstMonitorStub_;ICMonitoredStub(Kindkind,JitCode*stubCode,ICStub*firstMonitorStub);public:inlinevoidupdateFirstMonitorStub(ICStub*monitorStub){// This should only be called once: when the first optimized monitor stub// is added to the type monitor IC chain.MOZ_ASSERT(firstMonitorStub_&&firstMonitorStub_->isTypeMonitor_Fallback());firstMonitorStub_=monitorStub;}inlinevoidresetFirstMonitorStub(ICStub*monitorFallback){MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback());firstMonitorStub_=monitorFallback;}inlineICStub*firstMonitorStub()const{returnfirstMonitorStub_;}staticinlinesize_toffsetOfFirstMonitorStub(){returnoffsetof(ICMonitoredStub,firstMonitorStub_);}};classICCacheIR_Monitored:publicICMonitoredStub{constCacheIRStubInfo*stubInfo_;public:ICCacheIR_Monitored(JitCode*stubCode,ICStub*firstMonitorStub,constCacheIRStubInfo*stubInfo):ICMonitoredStub(ICStub::CacheIR_Monitored,stubCode,firstMonitorStub),stubInfo_(stubInfo){}staticICCacheIR_Monitored*Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICCacheIR_Monitored&other);voidnotePreliminaryObject(){extra_=1;}boolhasPreliminaryObject()const{returnextra_;}constCacheIRStubInfo*stubInfo()const{returnstubInfo_;}uint8_t*stubDataStart();};// Updated stubs are IC stubs that use a TypeUpdate IC to track// the status of heap typesets that need to be updated.classICUpdatedStub:publicICStub{protected:// Pointer to the start of the type updating stub chain.ICStub*firstUpdateStub_;staticconstuint32_tMAX_OPTIMIZED_STUBS=8;uint32_tnumOptimizedStubs_;ICUpdatedStub(Kindkind,JitCode*stubCode):ICStub(kind,ICStub::Updated,stubCode),firstUpdateStub_(nullptr),numOptimizedStubs_(0){}public:MOZ_MUST_USEboolinitUpdatingChain(JSContext*cx,ICStubSpace*space);MOZ_MUST_USEbooladdUpdateStubForValue(JSContext*cx,HandleScriptscript,HandleObjectobj,HandleIdid,HandleValueval);voidaddOptimizedUpdateStub(ICStub*stub){if(firstUpdateStub_->isTypeUpdate_Fallback()){stub->setNext(firstUpdateStub_);firstUpdateStub_=stub;}else{ICStub*iter=firstUpdateStub_;MOZ_ASSERT(iter->next()!=nullptr);while(!iter->next()->isTypeUpdate_Fallback())iter=iter->next();MOZ_ASSERT(iter->next()->next()==nullptr);stub->setNext(iter->next());iter->setNext(stub);}numOptimizedStubs_++;}inlineICStub*firstUpdateStub()const{returnfirstUpdateStub_;}voidresetUpdateStubChain(Zone*zone);boolhasTypeUpdateStub(ICStub::Kindkind){ICStub*stub=firstUpdateStub_;do{if(stub->kind()==kind)returntrue;stub=stub->next();}while(stub);returnfalse;}inlineuint32_tnumOptimizedStubs()const{returnnumOptimizedStubs_;}staticinlinesize_toffsetOfFirstUpdateStub(){returnoffsetof(ICUpdatedStub,firstUpdateStub_);}};classICCacheIR_Updated:publicICUpdatedStub{constCacheIRStubInfo*stubInfo_;GCPtrObjectGroupupdateStubGroup_;GCPtrIdupdateStubId_;public:ICCacheIR_Updated(JitCode*stubCode,constCacheIRStubInfo*stubInfo):ICUpdatedStub(ICStub::CacheIR_Updated,stubCode),stubInfo_(stubInfo),updateStubGroup_(nullptr),updateStubId_(JSID_EMPTY){}staticICCacheIR_Updated*Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICCacheIR_Updated&other);GCPtrObjectGroup&updateStubGroup(){returnupdateStubGroup_;}GCPtrId&updateStubId(){returnupdateStubId_;}voidnotePreliminaryObject(){extra_=1;}boolhasPreliminaryObject()const{returnextra_;}constCacheIRStubInfo*stubInfo()const{returnstubInfo_;}uint8_t*stubDataStart();};// Base class for stubcode compilers.classICStubCompiler{// Prevent GC in the middle of stub compilation.js::gc::AutoSuppressGCsuppressGC;public:usingEngine=ICStubEngine;protected:JSContext*cx;ICStub::Kindkind;Engineengine_;boolinStubFrame_;#ifdef DEBUGboolentersStubFrame_;uint32_tframePushedAtEnterStubFrame_;#endif// By default the stubcode key is just the kind.virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1);}virtualMOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm)=0;virtualvoidpostGenerateStubCode(MacroAssembler&masm,Handle<JitCode*>genCode){}JitCode*getStubCode();ICStubCompiler(JSContext*cx,ICStub::Kindkind,Engineengine):suppressGC(cx),cx(cx),kind(kind),engine_(engine),inStubFrame_(false)#ifdef DEBUG,entersStubFrame_(false),framePushedAtEnterStubFrame_(0)#endif{}// Push a payload specialized per compiler needed to execute stubs.voidPushStubPayload(MacroAssembler&masm,Registerscratch);voidpushStubPayload(MacroAssembler&masm,Registerscratch);// Emits a tail call to a VMFunction wrapper.MOZ_MUST_USEbooltailCallVM(constVMFunction&fun,MacroAssembler&masm);// Emits a normal (non-tail) call to a VMFunction wrapper.MOZ_MUST_USEboolcallVM(constVMFunction&fun,MacroAssembler&masm);// A stub frame is used when a stub wants to call into the VM without// performing a tail call. This is required for the return address// to pc mapping to work.voidenterStubFrame(MacroAssembler&masm,Registerscratch);voidassumeStubFrame(MacroAssembler&masm);voidleaveStubFrame(MacroAssembler&masm,boolcalledIntoIon=false);// Some stubs need to emit Gecko Profiler updates. This emits the guarding// jitcode for those stubs. If profiling is not enabled, jumps to the// given label.voidguardProfilingEnabled(MacroAssembler&masm,Registerscratch,Label*skip);public:staticinlineAllocatableGeneralRegisterSetavailableGeneralRegs(size_tnumInputs){AllocatableGeneralRegisterSetregs(GeneralRegisterSet::All());#if defined(JS_CODEGEN_ARM)MOZ_ASSERT(!regs.has(BaselineStackReg));MOZ_ASSERT(!regs.has(ICTailCallReg));regs.take(BaselineSecondScratchReg);#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)MOZ_ASSERT(!regs.has(BaselineStackReg));MOZ_ASSERT(!regs.has(ICTailCallReg));MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));#elif defined(JS_CODEGEN_ARM64)MOZ_ASSERT(!regs.has(PseudoStackPointer));MOZ_ASSERT(!regs.has(RealStackPointer));MOZ_ASSERT(!regs.has(ICTailCallReg));#elseMOZ_ASSERT(!regs.has(BaselineStackReg));#endifregs.take(BaselineFrameReg);regs.take(ICStubReg);#ifdef JS_CODEGEN_X64regs.take(ExtractTemp0);regs.take(ExtractTemp1);#endifswitch(numInputs){case0:break;case1:regs.take(R0);break;case2:regs.take(R0);regs.take(R1);break;default:MOZ_CRASH("Invalid numInputs");}returnregs;}protected:template<typenameT,typename...Args>T*newStub(Args&&...args){returnICStub::New<T>(cx,mozilla::Forward<Args>(args)...);}public:virtualICStub*getStub(ICStubSpace*space)=0;staticICStubSpace*StubSpaceForStub(boolmakesGCCalls,JSScript*outerScript,Engineengine){if(makesGCCalls){if(engine==ICStubCompiler::Engine::Baseline)returnouterScript->baselineScript()->fallbackStubSpace();returnouterScript->ionScript()->fallbackStubSpace();}returnouterScript->zone()->jitZone()->optimizedStubSpace();}ICStubSpace*getStubSpace(JSScript*outerScript){returnStubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind),outerScript,engine_);}};classSharedStubInfo{BaselineFrame*maybeFrame_;RootedScriptouterScript_;RootedScriptinnerScript_;ICEntry*icEntry_;public:SharedStubInfo(JSContext*cx,void*payload,ICEntry*entry);ICStubCompiler::Engineengine()const{returnmaybeFrame_?ICStubCompiler::Engine::Baseline:ICStubCompiler::Engine::IonSharedIC;}HandleScriptscript()const{MOZ_ASSERT(innerScript_);returninnerScript_;}HandleScriptinnerScript()const{MOZ_ASSERT(innerScript_);returninnerScript_;}HandleScriptouterScript(JSContext*cx);jsbytecode*pc()const{returnicEntry()->pc(innerScript());}uint32_tpcOffset()const{returnscript()->pcToOffset(pc());}BaselineFrame*frame()const{MOZ_ASSERT(maybeFrame_);returnmaybeFrame_;}BaselineFrame*maybeFrame()const{returnmaybeFrame_;}ICEntry*icEntry()const{returnicEntry_;}};// Monitored fallback stubs - as the name implies.classICMonitoredFallbackStub:publicICFallbackStub{protected:// Pointer to the fallback monitor stub.ICTypeMonitor_Fallback*fallbackMonitorStub_;ICMonitoredFallbackStub(Kindkind,JitCode*stubCode):ICFallbackStub(kind,ICStub::MonitoredFallback,stubCode),fallbackMonitorStub_(nullptr){}public:MOZ_MUST_USEboolinitMonitoringChain(JSContext*cx,ICStubSpace*space);MOZ_MUST_USEbooladdMonitorStubForValue(JSContext*cx,BaselineFrame*frame,StackTypeSet*types,HandleValueval);inlineICTypeMonitor_Fallback*fallbackMonitorStub()const{returnfallbackMonitorStub_;}staticinlinesize_toffsetOfFallbackMonitorStub(){returnoffsetof(ICMonitoredFallbackStub,fallbackMonitorStub_);}};// Base class for stub compilers that can generate multiple stubcodes.// These compilers need access to the JSOp they are compiling for.classICMultiStubCompiler:publicICStubCompiler{protected:JSOpop;// Stub keys for multi-stub kinds are composed of both the kind// and the op they are compiled for.virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op)<<17);}ICMultiStubCompiler(JSContext*cx,ICStub::Kindkind,JSOpop,Engineengine):ICStubCompiler(cx,kind,engine),op(op){}};// TypeCheckPrimitiveSetStub// Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given// value's type falls within a set of primitive types.classTypeCheckPrimitiveSetStub:publicICStub{friendclassICStubSpace;protected:inlinestaticuint16_tTypeToFlag(JSValueTypetype){return1u<<static_cast<unsigned>(type);}inlinestaticuint16_tValidFlags(){return((TypeToFlag(JSVAL_TYPE_OBJECT)<<1)-1)&~TypeToFlag(JSVAL_TYPE_MAGIC);}TypeCheckPrimitiveSetStub(Kindkind,JitCode*stubCode,uint16_tflags):ICStub(kind,stubCode){MOZ_ASSERT(kind==TypeMonitor_PrimitiveSet||kind==TypeUpdate_PrimitiveSet);MOZ_ASSERT(flags&&!(flags&~ValidFlags()));extra_=flags;}TypeCheckPrimitiveSetStub*updateTypesAndCode(uint16_tflags,JitCode*code){MOZ_ASSERT(flags&&!(flags&~ValidFlags()));if(!code)returnnullptr;extra_=flags;updateCode(code);returnthis;}public:uint16_ttypeFlags()const{returnextra_;}boolcontainsType(JSValueTypetype)const{MOZ_ASSERT(type<=JSVAL_TYPE_OBJECT);MOZ_ASSERT(type!=JSVAL_TYPE_MAGIC);returnextra_&TypeToFlag(type);}ICTypeMonitor_PrimitiveSet*toMonitorStub(){returntoTypeMonitor_PrimitiveSet();}ICTypeUpdate_PrimitiveSet*toUpdateStub(){returntoTypeUpdate_PrimitiveSet();}classCompiler:publicICStubCompiler{protected:TypeCheckPrimitiveSetStub*existingStub_;uint16_tflags_;virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(flags_)<<17);}public:Compiler(JSContext*cx,Kindkind,TypeCheckPrimitiveSetStub*existingStub,JSValueTypetype):ICStubCompiler(cx,kind,Engine::Baseline),existingStub_(existingStub),flags_((existingStub?existingStub->typeFlags():0)|TypeToFlag(type)){MOZ_ASSERT_IF(existingStub_,flags_!=existingStub_->typeFlags());}TypeCheckPrimitiveSetStub*updateStub(){MOZ_ASSERT(existingStub_);returnexistingStub_->updateTypesAndCode(flags_,getStubCode());}};};// TypeMonitor// The TypeMonitor fallback stub is not always a regular fallback stub. When// used for monitoring the values pushed by a bytecode it doesn't hold a// pointer to the IC entry, but rather back to the main fallback stub for the// IC (from which a pointer to the IC entry can be retrieved). When monitoring// the types of 'this', arguments or other values with no associated IC, there// is no main fallback stub, and the IC entry is referenced directly.classICTypeMonitor_Fallback:publicICStub{friendclassICStubSpace;staticconstuint32_tMAX_OPTIMIZED_STUBS=8;// Pointer to the main fallback stub for the IC or to the main IC entry,// depending on hasFallbackStub.union{ICMonitoredFallbackStub*mainFallbackStub_;ICEntry*icEntry_;};// Pointer to the first monitor stub.ICStub*firstMonitorStub_;// Address of the last monitor stub's field pointing to this// fallback monitor stub. This will get updated when new// monitor stubs are created and added.ICStub**lastMonitorStubPtrAddr_;// Count of optimized type monitor stubs in this chain.uint32_tnumOptimizedMonitorStubs_:7;uint32_tinvalid_:1;// Whether this has a fallback stub referring to the IC entry.boolhasFallbackStub_:1;// Index of 'this' or argument which is being monitored, or BYTECODE_INDEX// if this is monitoring the types of values pushed at some bytecode.uint32_targumentIndex_:23;staticconstuint32_tBYTECODE_INDEX=(1<<23)-1;ICTypeMonitor_Fallback(JitCode*stubCode,ICMonitoredFallbackStub*mainFallbackStub,uint32_targumentIndex):ICStub(ICStub::TypeMonitor_Fallback,stubCode),mainFallbackStub_(mainFallbackStub),firstMonitorStub_(thisFromCtor()),lastMonitorStubPtrAddr_(nullptr),numOptimizedMonitorStubs_(0),invalid_(false),hasFallbackStub_(mainFallbackStub!=nullptr),argumentIndex_(argumentIndex){}ICTypeMonitor_Fallback*thisFromCtor(){returnthis;}voidaddOptimizedMonitorStub(ICStub*stub){MOZ_ASSERT(!invalid());stub->setNext(this);MOZ_ASSERT((lastMonitorStubPtrAddr_!=nullptr)==(numOptimizedMonitorStubs_||!hasFallbackStub_));if(lastMonitorStubPtrAddr_)*lastMonitorStubPtrAddr_=stub;if(numOptimizedMonitorStubs_==0){MOZ_ASSERT(firstMonitorStub_==this);firstMonitorStub_=stub;}else{MOZ_ASSERT(firstMonitorStub_!=nullptr);}lastMonitorStubPtrAddr_=stub->addressOfNext();numOptimizedMonitorStubs_++;}public:boolhasStub(ICStub::Kindkind){ICStub*stub=firstMonitorStub_;do{if(stub->kind()==kind)returntrue;stub=stub->next();}while(stub);returnfalse;}inlineICFallbackStub*mainFallbackStub()const{MOZ_ASSERT(hasFallbackStub_);returnmainFallbackStub_;}inlineICEntry*icEntry()const{returnhasFallbackStub_?mainFallbackStub()->icEntry():icEntry_;}inlineICStub*firstMonitorStub()const{returnfirstMonitorStub_;}staticinlinesize_toffsetOfFirstMonitorStub(){returnoffsetof(ICTypeMonitor_Fallback,firstMonitorStub_);}inlineuint32_tnumOptimizedMonitorStubs()const{returnnumOptimizedMonitorStubs_;}voidsetInvalid(){invalid_=1;}boolinvalid()const{returninvalid_;}inlineboolmonitorsThis()const{returnargumentIndex_==0;}inlineboolmonitorsArgument(uint32_t*pargument)const{if(argumentIndex_>0&&argumentIndex_<BYTECODE_INDEX){*pargument=argumentIndex_-1;returntrue;}returnfalse;}inlineboolmonitorsBytecode()const{returnargumentIndex_==BYTECODE_INDEX;}// Fixup the IC entry as for a normal fallback stub, for this/arguments.voidfixupICEntry(ICEntry*icEntry){MOZ_ASSERT(!hasFallbackStub_);MOZ_ASSERT(icEntry_==nullptr);MOZ_ASSERT(lastMonitorStubPtrAddr_==nullptr);icEntry_=icEntry;lastMonitorStubPtrAddr_=icEntry_->addressOfFirstStub();}// Create a new monitor stub for the type of the given value, and// add it to this chain.MOZ_MUST_USEbooladdMonitorStubForValue(JSContext*cx,BaselineFrame*frame,StackTypeSet*types,HandleValueval);voidresetMonitorStubChain(Zone*zone);// Compiler for this stub kind.classCompiler:publicICStubCompiler{ICMonitoredFallbackStub*mainFallbackStub_;uint32_targumentIndex_;protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,ICMonitoredFallbackStub*mainFallbackStub):ICStubCompiler(cx,ICStub::TypeMonitor_Fallback,Engine::Baseline),mainFallbackStub_(mainFallbackStub),argumentIndex_(BYTECODE_INDEX){}Compiler(JSContext*cx,uint32_targumentIndex):ICStubCompiler(cx,ICStub::TypeMonitor_Fallback,Engine::Baseline),mainFallbackStub_(nullptr),argumentIndex_(argumentIndex){}ICTypeMonitor_Fallback*getStub(ICStubSpace*space){returnnewStub<ICTypeMonitor_Fallback>(space,getStubCode(),mainFallbackStub_,argumentIndex_);}};};classICTypeMonitor_PrimitiveSet:publicTypeCheckPrimitiveSetStub{friendclassICStubSpace;ICTypeMonitor_PrimitiveSet(JitCode*stubCode,uint16_tflags):TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet,stubCode,flags){}public:classCompiler:publicTypeCheckPrimitiveSetStub::Compiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,ICTypeMonitor_PrimitiveSet*existingStub,JSValueTypetype):TypeCheckPrimitiveSetStub::Compiler(cx,TypeMonitor_PrimitiveSet,existingStub,type){}ICTypeMonitor_PrimitiveSet*updateStub(){TypeCheckPrimitiveSetStub*stub=this->TypeCheckPrimitiveSetStub::Compiler::updateStub();if(!stub)returnnullptr;returnstub->toMonitorStub();}ICTypeMonitor_PrimitiveSet*getStub(ICStubSpace*space){MOZ_ASSERT(!existingStub_);returnnewStub<ICTypeMonitor_PrimitiveSet>(space,getStubCode(),flags_);}};};classICTypeMonitor_SingleObject:publicICStub{friendclassICStubSpace;GCPtrObjectobj_;ICTypeMonitor_SingleObject(JitCode*stubCode,JSObject*obj);public:GCPtrObject&object(){returnobj_;}staticsize_toffsetOfObject(){returnoffsetof(ICTypeMonitor_SingleObject,obj_);}classCompiler:publicICStubCompiler{protected:HandleObjectobj_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,HandleObjectobj):ICStubCompiler(cx,TypeMonitor_SingleObject,Engine::Baseline),obj_(obj){}ICTypeMonitor_SingleObject*getStub(ICStubSpace*space){returnnewStub<ICTypeMonitor_SingleObject>(space,getStubCode(),obj_);}};};classICTypeMonitor_ObjectGroup:publicICStub{friendclassICStubSpace;GCPtrObjectGroupgroup_;ICTypeMonitor_ObjectGroup(JitCode*stubCode,ObjectGroup*group);public:GCPtrObjectGroup&group(){returngroup_;}staticsize_toffsetOfGroup(){returnoffsetof(ICTypeMonitor_ObjectGroup,group_);}classCompiler:publicICStubCompiler{protected:HandleObjectGroupgroup_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,HandleObjectGroupgroup):ICStubCompiler(cx,TypeMonitor_ObjectGroup,Engine::Baseline),group_(group){}ICTypeMonitor_ObjectGroup*getStub(ICStubSpace*space){returnnewStub<ICTypeMonitor_ObjectGroup>(space,getStubCode(),group_);}};};classICTypeMonitor_AnyValue:publicICStub{friendclassICStubSpace;explicitICTypeMonitor_AnyValue(JitCode*stubCode):ICStub(TypeMonitor_AnyValue,stubCode){}public:classCompiler:publicICStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx):ICStubCompiler(cx,TypeMonitor_AnyValue,Engine::Baseline){}ICTypeMonitor_AnyValue*getStub(ICStubSpace*space){returnnewStub<ICTypeMonitor_AnyValue>(space,getStubCode());}};};// BinaryArith// JSOP_ADD, JSOP_SUB, JSOP_MUL, JOP_DIV, JSOP_MOD// JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR// JSOP_LSH, JSOP_RSH, JSOP_URSHclassICBinaryArith_Fallback:publicICFallbackStub{friendclassICStubSpace;explicitICBinaryArith_Fallback(JitCode*stubCode):ICFallbackStub(BinaryArith_Fallback,stubCode){extra_=0;}staticconstuint16_tSAW_DOUBLE_RESULT_BIT=0x1;staticconstuint16_tUNOPTIMIZABLE_OPERANDS_BIT=0x2;public:staticconstuint32_tMAX_OPTIMIZED_STUBS=8;boolsawDoubleResult()const{returnextra_&SAW_DOUBLE_RESULT_BIT;}voidsetSawDoubleResult(){extra_|=SAW_DOUBLE_RESULT_BIT;}boolhadUnoptimizableOperands()const{returnextra_&UNOPTIMIZABLE_OPERANDS_BIT;}voidnoteUnoptimizableOperands(){extra_|=UNOPTIMIZABLE_OPERANDS_BIT;}// Compiler for this stub kind.classCompiler:publicICStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx,Engineengine):ICStubCompiler(cx,ICStub::BinaryArith_Fallback,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_Fallback>(space,getStubCode());}};};classICBinaryArith_Int32:publicICStub{friendclassICStubSpace;ICBinaryArith_Int32(JitCode*stubCode,boolallowDouble):ICStub(BinaryArith_Int32,stubCode){extra_=allowDouble;}public:boolallowDouble()const{returnextra_;}// Compiler for this stub kind.classCompiler:publicICStubCompiler{protected:JSOpop_;boolallowDouble_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);// Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles.virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op_)<<17)|(static_cast<int32_t>(allowDouble_)<<25);}public:Compiler(JSContext*cx,JSOpop,Engineengine,boolallowDouble):ICStubCompiler(cx,ICStub::BinaryArith_Int32,engine),op_(op),allowDouble_(allowDouble){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_Int32>(space,getStubCode(),allowDouble_);}};};classICBinaryArith_StringConcat:publicICStub{friendclassICStubSpace;explicitICBinaryArith_StringConcat(JitCode*stubCode):ICStub(BinaryArith_StringConcat,stubCode){}public:classCompiler:publicICStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx,Engineengine):ICStubCompiler(cx,ICStub::BinaryArith_StringConcat,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_StringConcat>(space,getStubCode());}};};classICBinaryArith_StringObjectConcat:publicICStub{friendclassICStubSpace;ICBinaryArith_StringObjectConcat(JitCode*stubCode,boollhsIsString):ICStub(BinaryArith_StringObjectConcat,stubCode){extra_=lhsIsString;}public:boollhsIsString()const{returnextra_;}classCompiler:publicICStubCompiler{protected:boollhsIsString_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(lhsIsString_)<<17);}public:Compiler(JSContext*cx,Engineengine,boollhsIsString):ICStubCompiler(cx,ICStub::BinaryArith_StringObjectConcat,engine),lhsIsString_(lhsIsString){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_StringObjectConcat>(space,getStubCode(),lhsIsString_);}};};classICBinaryArith_Double:publicICStub{friendclassICStubSpace;explicitICBinaryArith_Double(JitCode*stubCode):ICStub(BinaryArith_Double,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::BinaryArith_Double,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_Double>(space,getStubCode());}};};classICBinaryArith_BooleanWithInt32:publicICStub{friendclassICStubSpace;ICBinaryArith_BooleanWithInt32(JitCode*stubCode,boollhsIsBool,boolrhsIsBool):ICStub(BinaryArith_BooleanWithInt32,stubCode){MOZ_ASSERT(lhsIsBool||rhsIsBool);extra_=0;if(lhsIsBool)extra_|=1;if(rhsIsBool)extra_|=2;}public:boollhsIsBoolean()const{returnextra_&1;}boolrhsIsBoolean()const{returnextra_&2;}classCompiler:publicICStubCompiler{protected:JSOpop_;boollhsIsBool_;boolrhsIsBool_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op_)<<17)|(static_cast<int32_t>(lhsIsBool_)<<25)|(static_cast<int32_t>(rhsIsBool_)<<26);}public:Compiler(JSContext*cx,JSOpop,Engineengine,boollhsIsBool,boolrhsIsBool):ICStubCompiler(cx,ICStub::BinaryArith_BooleanWithInt32,engine),op_(op),lhsIsBool_(lhsIsBool),rhsIsBool_(rhsIsBool){MOZ_ASSERT(op_==JSOP_ADD||op_==JSOP_SUB||op_==JSOP_BITOR||op_==JSOP_BITAND||op_==JSOP_BITXOR);MOZ_ASSERT(lhsIsBool_||rhsIsBool_);}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_BooleanWithInt32>(space,getStubCode(),lhsIsBool_,rhsIsBool_);}};};classICBinaryArith_DoubleWithInt32:publicICStub{friendclassICStubSpace;ICBinaryArith_DoubleWithInt32(JitCode*stubCode,boollhsIsDouble):ICStub(BinaryArith_DoubleWithInt32,stubCode){extra_=lhsIsDouble;}public:boollhsIsDouble()const{returnextra_;}classCompiler:publicICMultiStubCompiler{protected:boollhsIsDouble_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op)<<17)|(static_cast<int32_t>(lhsIsDouble_)<<25);}public:Compiler(JSContext*cx,JSOpop,Engineengine,boollhsIsDouble):ICMultiStubCompiler(cx,ICStub::BinaryArith_DoubleWithInt32,op,engine),lhsIsDouble_(lhsIsDouble){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICBinaryArith_DoubleWithInt32>(space,getStubCode(),lhsIsDouble_);}};};// UnaryArith// JSOP_BITNOT// JSOP_NEGclassICUnaryArith_Fallback:publicICFallbackStub{friendclassICStubSpace;explicitICUnaryArith_Fallback(JitCode*stubCode):ICFallbackStub(UnaryArith_Fallback,stubCode){extra_=0;}public:staticconstuint32_tMAX_OPTIMIZED_STUBS=8;boolsawDoubleResult(){returnextra_;}voidsetSawDoubleResult(){extra_=1;}// Compiler for this stub kind.classCompiler:publicICStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx,Engineengine):ICStubCompiler(cx,ICStub::UnaryArith_Fallback,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICUnaryArith_Fallback>(space,getStubCode());}};};classICUnaryArith_Int32:publicICStub{friendclassICStubSpace;explicitICUnaryArith_Int32(JitCode*stubCode):ICStub(UnaryArith_Int32,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::UnaryArith_Int32,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICUnaryArith_Int32>(space,getStubCode());}};};classICUnaryArith_Double:publicICStub{friendclassICStubSpace;explicitICUnaryArith_Double(JitCode*stubCode):ICStub(UnaryArith_Double,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::UnaryArith_Double,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICUnaryArith_Double>(space,getStubCode());}};};// Compare// JSOP_LT// JSOP_LE// JSOP_GT// JSOP_GE// JSOP_EQ// JSOP_NE// JSOP_STRICTEQ// JSOP_STRICTNEclassICCompare_Fallback:publicICFallbackStub{friendclassICStubSpace;explicitICCompare_Fallback(JitCode*stubCode):ICFallbackStub(ICStub::Compare_Fallback,stubCode){}public:staticconstuint32_tMAX_OPTIMIZED_STUBS=8;staticconstsize_tUNOPTIMIZABLE_ACCESS_BIT=0;voidnoteUnoptimizableAccess(){extra_|=(1u<<UNOPTIMIZABLE_ACCESS_BIT);}boolhadUnoptimizableAccess()const{returnextra_&(1u<<UNOPTIMIZABLE_ACCESS_BIT);}// Compiler for this stub kind.classCompiler:publicICStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx,Engineengine):ICStubCompiler(cx,ICStub::Compare_Fallback,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Fallback>(space,getStubCode());}};};classICCompare_Int32:publicICStub{friendclassICStubSpace;explicitICCompare_Int32(JitCode*stubCode):ICStub(ICStub::Compare_Int32,stubCode){}public:// Compiler for this stub kind.classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_Int32,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Int32>(space,getStubCode());}};};classICCompare_Double:publicICStub{friendclassICStubSpace;explicitICCompare_Double(JitCode*stubCode):ICStub(ICStub::Compare_Double,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_Double,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Double>(space,getStubCode());}};};classICCompare_NumberWithUndefined:publicICStub{friendclassICStubSpace;ICCompare_NumberWithUndefined(JitCode*stubCode,boollhsIsUndefined):ICStub(ICStub::Compare_NumberWithUndefined,stubCode){extra_=lhsIsUndefined;}public:boollhsIsUndefined(){returnextra_;}classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);boollhsIsUndefined;public:Compiler(JSContext*cx,JSOpop,Engineengine,boollhsIsUndefined):ICMultiStubCompiler(cx,ICStub::Compare_NumberWithUndefined,op,engine),lhsIsUndefined(lhsIsUndefined){}virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op)<<17)|(static_cast<int32_t>(lhsIsUndefined)<<25);}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_NumberWithUndefined>(space,getStubCode(),lhsIsUndefined);}};};classICCompare_String:publicICStub{friendclassICStubSpace;explicitICCompare_String(JitCode*stubCode):ICStub(ICStub::Compare_String,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_String,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_String>(space,getStubCode());}};};classICCompare_Symbol:publicICStub{friendclassICStubSpace;explicitICCompare_Symbol(JitCode*stubCode):ICStub(ICStub::Compare_Symbol,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_Symbol,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Symbol>(space,getStubCode());}};};classICCompare_Boolean:publicICStub{friendclassICStubSpace;explicitICCompare_Boolean(JitCode*stubCode):ICStub(ICStub::Compare_Boolean,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_Boolean,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Boolean>(space,getStubCode());}};};classICCompare_Object:publicICStub{friendclassICStubSpace;explicitICCompare_Object(JitCode*stubCode):ICStub(ICStub::Compare_Object,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,JSOpop,Engineengine):ICMultiStubCompiler(cx,ICStub::Compare_Object,op,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Object>(space,getStubCode());}};};classICCompare_ObjectWithUndefined:publicICStub{friendclassICStubSpace;explicitICCompare_ObjectWithUndefined(JitCode*stubCode):ICStub(ICStub::Compare_ObjectWithUndefined,stubCode){}public:classCompiler:publicICMultiStubCompiler{protected:MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);boollhsIsUndefined;boolcompareWithNull;public:Compiler(JSContext*cx,JSOpop,Engineengine,boollhsIsUndefined,boolcompareWithNull):ICMultiStubCompiler(cx,ICStub::Compare_ObjectWithUndefined,op,engine),lhsIsUndefined(lhsIsUndefined),compareWithNull(compareWithNull){}virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op)<<17)|(static_cast<int32_t>(lhsIsUndefined)<<25)|(static_cast<int32_t>(compareWithNull)<<26);}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_ObjectWithUndefined>(space,getStubCode());}};};classICCompare_Int32WithBoolean:publicICStub{friendclassICStubSpace;ICCompare_Int32WithBoolean(JitCode*stubCode,boollhsIsInt32):ICStub(ICStub::Compare_Int32WithBoolean,stubCode){extra_=lhsIsInt32;}public:boollhsIsInt32()const{returnextra_;}// Compiler for this stub kind.classCompiler:publicICStubCompiler{protected:JSOpop_;boollhsIsInt32_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(op_)<<17)|(static_cast<int32_t>(lhsIsInt32_)<<25);}public:Compiler(JSContext*cx,JSOpop,Engineengine,boollhsIsInt32):ICStubCompiler(cx,ICStub::Compare_Int32WithBoolean,engine),op_(op),lhsIsInt32_(lhsIsInt32){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICCompare_Int32WithBoolean>(space,getStubCode(),lhsIsInt32_);}};};// Enum for stubs handling a combination of typed arrays and typed objects.enumTypedThingLayout{Layout_TypedArray,Layout_OutlineTypedObject,Layout_InlineTypedObject};staticinlineTypedThingLayoutGetTypedThingLayout(constClass*clasp){if(IsTypedArrayClass(clasp))returnLayout_TypedArray;if(IsOutlineTypedObjectClass(clasp))returnLayout_OutlineTypedObject;if(IsInlineTypedObjectClass(clasp))returnLayout_InlineTypedObject;MOZ_CRASH("Bad object class");}boolIsPreliminaryObject(JSObject*obj);voidStripPreliminaryObjectStubs(JSContext*cx,ICFallbackStub*stub);MOZ_MUST_USEboolCheckHasNoSuchOwnProperty(JSContext*cx,JSObject*obj,jsidid);MOZ_MUST_USEboolCheckHasNoSuchProperty(JSContext*cx,JSObject*obj,jsidid,JSObject**lastProto=nullptr,size_t*protoChainDepthOut=nullptr);voidCheckForTypedObjectWithDetachedStorage(JSContext*cx,MacroAssembler&masm,Label*failure);voidLoadTypedThingData(MacroAssembler&masm,TypedThingLayoutlayout,Registerobj,Registerresult);boolIsPrimitiveArrayTypedObject(JSObject*obj);Scalar::TypeTypedThingElementType(JSObject*obj);boolTypedThingRequiresFloatingPoint(JSObject*obj);voidLoadTypedThingLength(MacroAssembler&masm,TypedThingLayoutlayout,Registerobj,Registerresult);classICGetProp_Fallback:publicICMonitoredFallbackStub{friendclassICStubSpace;explicitICGetProp_Fallback(JitCode*stubCode):ICMonitoredFallbackStub(ICStub::GetProp_Fallback,stubCode){}public:staticconstsize_tUNOPTIMIZABLE_ACCESS_BIT=0;staticconstsize_tACCESSED_GETTER_BIT=1;voidnoteUnoptimizableAccess(){extra_|=(1u<<UNOPTIMIZABLE_ACCESS_BIT);}boolhadUnoptimizableAccess()const{returnextra_&(1u<<UNOPTIMIZABLE_ACCESS_BIT);}voidnoteAccessedGetter(){extra_|=(1u<<ACCESSED_GETTER_BIT);}boolhasAccessedGetter()const{returnextra_&(1u<<ACCESSED_GETTER_BIT);}classCompiler:publicICStubCompiler{protected:CodeOffsetbailoutReturnOffset_;boolhasReceiver_;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);voidpostGenerateStubCode(MacroAssembler&masm,Handle<JitCode*>code);virtualint32_tgetKey()const{returnstatic_cast<int32_t>(engine_)|(static_cast<int32_t>(kind)<<1)|(static_cast<int32_t>(hasReceiver_)<<17);}public:explicitCompiler(JSContext*cx,Engineengine,boolhasReceiver=false):ICStubCompiler(cx,ICStub::GetProp_Fallback,engine),hasReceiver_(hasReceiver){}ICStub*getStub(ICStubSpace*space){ICGetProp_Fallback*stub=newStub<ICGetProp_Fallback>(space,getStubCode());if(!stub||!stub->initMonitoringChain(cx,space))returnnullptr;returnstub;}};};staticinlineuint32_tSimpleTypeDescrKey(SimpleTypeDescr*descr){if(descr->is<ScalarTypeDescr>())returnuint32_t(descr->as<ScalarTypeDescr>().type())<<1;return(uint32_t(descr->as<ReferenceTypeDescr>().type())<<1)|1;}inlineboolSimpleTypeDescrKeyIsScalar(uint32_tkey){return!(key&1);}inlineScalarTypeDescr::TypeScalarTypeFromSimpleTypeDescrKey(uint32_tkey){MOZ_ASSERT(SimpleTypeDescrKeyIsScalar(key));returnScalarTypeDescr::Type(key>>1);}inlineReferenceTypeDescr::TypeReferenceTypeFromSimpleTypeDescrKey(uint32_tkey){MOZ_ASSERT(!SimpleTypeDescrKeyIsScalar(key));returnReferenceTypeDescr::Type(key>>1);}// JSOP_NEWARRAY// JSOP_NEWINITclassICNewArray_Fallback:publicICFallbackStub{friendclassICStubSpace;GCPtrObjecttemplateObject_;// The group used for objects created here is always available, even if the// template object itself is not.GCPtrObjectGrouptemplateGroup_;ICNewArray_Fallback(JitCode*stubCode,ObjectGroup*templateGroup):ICFallbackStub(ICStub::NewArray_Fallback,stubCode),templateObject_(nullptr),templateGroup_(templateGroup){}public:classCompiler:publicICStubCompiler{RootedObjectGrouptemplateGroup;MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:Compiler(JSContext*cx,ObjectGroup*templateGroup,Engineengine):ICStubCompiler(cx,ICStub::NewArray_Fallback,engine),templateGroup(cx,templateGroup){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICNewArray_Fallback>(space,getStubCode(),templateGroup);}};GCPtrObject&templateObject(){returntemplateObject_;}voidsetTemplateObject(JSObject*obj){MOZ_ASSERT(obj->group()==templateGroup());templateObject_=obj;}GCPtrObjectGroup&templateGroup(){returntemplateGroup_;}voidsetTemplateGroup(ObjectGroup*group){templateObject_=nullptr;templateGroup_=group;}};// JSOP_NEWOBJECTclassICNewObject_Fallback:publicICFallbackStub{friendclassICStubSpace;GCPtrObjecttemplateObject_;explicitICNewObject_Fallback(JitCode*stubCode):ICFallbackStub(ICStub::NewObject_Fallback,stubCode),templateObject_(nullptr){}public:classCompiler:publicICStubCompiler{MOZ_MUST_USEboolgenerateStubCode(MacroAssembler&masm);public:explicitCompiler(JSContext*cx,Engineengine):ICStubCompiler(cx,ICStub::NewObject_Fallback,engine){}ICStub*getStub(ICStubSpace*space){returnnewStub<ICNewObject_Fallback>(space,getStubCode());}};GCPtrObject&templateObject(){returntemplateObject_;}voidsetTemplateObject(JSObject*obj){templateObject_=obj;}};classICNewObject_WithTemplate:publicICStub{friendclassICStubSpace;explicitICNewObject_WithTemplate(JitCode*stubCode):ICStub(ICStub::NewObject_WithTemplate,stubCode){}};}// namespace jit}// namespace js#endif /* jit_SharedIC_h */